﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using DictationToolSilverlight.View;

namespace TextCompare
{
    class TextBlockFormatter : IFormatter
    {
        private Paragraph paragraph;
        private RichTextBox textBlock;

        public TextBlockFormatter(RichTextBox textBlock)
        {
            this.textBlock = textBlock;
            textBlock.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
            textBlock.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
            textBlock.IsReadOnly = true;

            paragraph = new Paragraph();
            textBlock.Blocks.Clear();
            textBlock.Blocks.Add(paragraph);
        }

        public void Write(ITextMatcher textMatcher, IEnumerable<MatchPoint> points)
        {
            if (textMatcher.SourceCount == 0 || textMatcher.TargetCount == 0 || points == null)
                return;

            if (points.Count() == 0)
            {
                WriteAll(textMatcher.Source, textMatcher.Target);
                return;
            }

            WriteByPoint(textMatcher, points);
        }

        private void WriteAll(string source, string target)
        {
            CreateContainers(target, Direction.Right);
            CreateContainers(source, Direction.Down);
        }

        private void WriteByPoint(ITextMatcher textMatcher, IEnumerable<MatchPoint> points)
        {
            foreach (var point in points)
            {
                switch (point.Direction)
                {
                    case Direction.DownRight:
                        CreateContainers(textMatcher.GetSourceSubString(point.X, point.Y), point.Direction);
                        break;
                    case Direction.Down:
                        CreateContainers(textMatcher.GetSourceSubString(point.X, point.Y), point.Direction);
                        break;
                    case Direction.Right:
                        CreateContainers(textMatcher.GetTargetSubString(point.X, point.Y), point.Direction);
                        break;
                    default:
                        break;
                }
            }
        }

        private void CreateContainers(string text, Direction direction)
        {
            if (text.Contains("\n"))
            {
                int index = -1;
                while ((index = text.IndexOf("\n")) != -1)
                {
                    string str = text.Substring(0, index);
                    textBlock.Selection.Insert(CreateContainer(styles[direction].GetInlineExInstance(str)));
                    paragraph.Inlines.Add(new Run() { Text = "\n" });
                    text = text.Remove(0, index + 1);
                }
            }
            textBlock.Selection.Insert(CreateContainer(styles[direction].GetInlineExInstance(text)));
        }

        private static Dictionary<Direction, Inlines> styles = new Dictionary<Direction, Inlines>
        {
            { Direction.Down, new HilightInline()},
            { Direction.Right, new StrikeInline()},
            { Direction.DownRight, new NomalInline()}
        };

        private InlineUIContainer CreateContainer(InlinesEx inline)
        {
            InlineUIContainer container = new InlineUIContainer();

            container.Child = inline;

            return container;
        }

        private abstract class Inlines
        {
            public abstract InlinesEx GetInlineExInstance(string text);
        }

        private class HilightInline : Inlines
        {
            public override InlinesEx GetInlineExInstance(string text)
            {
                InlinesEx inline = new InlinesEx(text);
                inline.Background = background;
                inline.BorderThickness = new Thickness(1);
                inline.BorderBrush = borderBrush;

                return inline;
            }

            private readonly SolidColorBrush background = new SolidColorBrush(Colors.Green);
            private readonly SolidColorBrush borderBrush = new SolidColorBrush(Colors.Green);
        }

        private class StrikeInline : Inlines
        {
            public override InlinesEx GetInlineExInstance(string text)
            {
                InlinesEx inline = new InlinesEx(text);
                inline.StrikeLineEnable = true;
                inline.Foreground = new SolidColorBrush(Colors.Red);

                return inline;
            }
        }

        private class NomalInline : Inlines
        {
            public override InlinesEx GetInlineExInstance(string text)
            {
                InlinesEx inline = new InlinesEx(text);

                return inline;
            } 
        }
    }
}
